package com.sunsharing.wsdlcall.wsdl4j;

import org.apache.axis.wsdl.gen.Parser;
import org.apache.axis.wsdl.symbolTable.*;
import org.apache.log4j.Logger;

import javax.wsdl.Binding;
import javax.wsdl.Operation;
import javax.wsdl.Port;
import javax.wsdl.Service;
import javax.wsdl.extensions.soap.SOAPAddress;
import javax.xml.namespace.QName;
import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: Administrator
 * Date: 12-7-19
 * Time: 上午11:29
 * To change this template use File | Settings | File Templates.
 */
public class WsdlParse {
    static Logger logger = Logger.getLogger(WsdlParse.class);
    private Parser wsdlParser;
    public WsdlService parseWsdl(String wsdl,String operationName,String serviceId)throws Exception
    {
        WsdlService wsdlService = new WsdlService();
        wsdlParser = new Parser();
        logger.info("Reading WSDL document from '" + wsdl + "'");
        wsdlParser.run(wsdl);
        String portName = null;
        try {
            portName = operationName.substring(operationName.indexOf("(") + 1,
                    operationName.indexOf(")"));
            operationName = operationName.substring(0, operationName.indexOf("("));
        } catch (Exception ignored) {
        }

        Service service = selectService(null, null);
        Operation operation = null;

        //org.apache.axis.client.Service dpf = new org.apache.axis.client.Service(wsdlParser, service.getQName());

        Port port = selectPort(service.getPorts(), portName);
        if (portName == null) {
            portName = port.getName();
        }

        SymbolTable symbolTable = wsdlParser.getSymbolTable();
        Binding binding = port.getBinding();
        BindingEntry bEntry =
                symbolTable.getBindingEntry(binding.getQName());
        Parameters parameters = null;
        Iterator i = bEntry.getParameters().keySet().iterator();

        while (i.hasNext()) {
            Operation o = (Operation) i.next();
            if (o.getName().equals(operationName)) {
                operation = o;
                parameters = (Parameters) bEntry.getParameters().get(o);
                break;
            }
        }
        if ((operation == null) || (parameters == null)) {
            throw new RuntimeException(operationName + " was not found.");
        }
        wsdlService.setQname(service.getQName());
        wsdlService.setWsdlParser(wsdlParser);
        wsdlService.setServiceId(serviceId);
        wsdlService.setMethodName(operationName);
        wsdlService.setPortName(portName);
        wsdlService.setWsdl(wsdl);
        wsdlService.setTargetNameSpace(wsdlParser.getCurrentDefinition().getTargetNamespace());
        // loop over paramters and set up in/out params
        for (int j = 0; j < parameters.list.size(); ++j) {
            Parameter p = (Parameter) parameters.list.get(j);
            WsdlOperatorElement ele = new WsdlOperatorElement();
            if (p.getMode() == 1) {           // IN
                ele.setName(p.getName());
                ele.setType(p);
                wsdlService.addInput(ele);
               // inNames.add(p.getQName().getLocalPart());
               // inTypes.add(p);
            } else if (p.getMode() == 2) {    // OUT
                ele.setName(p.getQName().getLocalPart());
                ele.setType(p);
                wsdlService.setOutput(ele);
                //outNames.add(p.getQName().getLocalPart());
            } else if (p.getMode() == 3) {    // INOUT
//                inNames.add(p.getQName().getLocalPart());
//                inTypes.add(p);
//                outNames.add(p.getQName().getLocalPart());
            }
        }

        if (parameters.returnParam != null) {

//            if(!parameters.returnParam.getType().isBaseType()) {
//                ((org.apache.axis.client.Call)call).registerTypeMapping(org.w3c.dom.Element.class, parameters.returnParam.getType().getQName(),
//                        new ElementSerializerFactory(),
//                        new ElementDeserializerFactory());
//            }

            // Get the QName for the return Type
            QName returnType = org.apache.axis.wsdl.toJava.Utils.getXSIType(
                    parameters.returnParam);
            QName returnQName = parameters.returnParam.getQName();
            WsdlOperatorElement ele = new WsdlOperatorElement();
            ele.setName(parameters.returnParam.getQName().getLocalPart());
            ele.setType(parameters.returnParam);
            wsdlService.setOutput(ele);
            //outNames.add(returnQName.getLocalPart());
        }

        return wsdlService;
    }

    /**
     * Method selectService
     *
     * @param serviceNS
     * @param serviceName
     *
     * @return
     *
     * @throws Exception
     */
    private Service selectService(String serviceNS, String serviceName)
            throws Exception {
        QName serviceQName = (((serviceNS != null)
                && (serviceName != null))
                ? new QName(serviceNS, serviceName)
                : null);
        ServiceEntry serviceEntry = (ServiceEntry) getSymTabEntry(serviceQName,
                ServiceEntry.class);
        return serviceEntry.getService();
    }

    /**
     * Method getSymTabEntry
     *
     * @param qname
     * @param cls
     *
     * @return
     */
    private SymTabEntry getSymTabEntry(QName qname, Class cls) {
        HashMap map = wsdlParser.getSymbolTable().getHashMap();
        Iterator iterator = map.entrySet().iterator();

        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            QName key = (QName) entry.getKey();
            Vector v = (Vector) entry.getValue();

            if ((qname == null) || qname.equals(qname)) {
                for (int i = 0; i < v.size(); ++i) {
                    SymTabEntry symTabEntry = (SymTabEntry) v.elementAt(i);

                    if (cls.isInstance(symTabEntry)) {
                        return symTabEntry;
                    }
                }
            }
        }
        return null;
    }

    /**
     * Method selectPort
     *
     * @param ports
     * @param portName
     *
     * @return
     *
     * @throws Exception
     */
    private Port selectPort(Map ports, String portName) throws Exception {
        Iterator valueIterator = ports.keySet().iterator();
        while (valueIterator.hasNext()) {
            String name = (String) valueIterator.next();

            if ((portName == null) || (portName.length() == 0)) {
                Port port = (Port) ports.get(name);
                List list = port.getExtensibilityElements();

                for (int i = 0; (list != null) && (i < list.size()); i++) {
                    Object obj = list.get(i);
                    if (obj instanceof SOAPAddress) {
                        return port;
                    }
                }
            } else if ((name != null) && name.equals(portName)) {
                return (Port) ports.get(name);
            }
        }
        return null;
    }



}
